package com.boarsoft.boar.config.file.action;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import com.boarsoft.boar.BaseConfig;
import com.boarsoft.boar.app.AppBiz;
import com.boarsoft.boar.entity.AppInfo;
import com.boarsoft.boar.entity.FileVersion;
import com.boarsoft.boar.file.FileVersionBiz;
import com.boarsoft.boar.file.action.FileVersionAction;
import com.boarsoft.common.util.StringUtil;
import com.boarsoft.common.util.ZipUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.config.entity.FileConfigInfo;
import com.boarsoft.boar.config.service.ConfigFileService;
import com.boarsoft.boar.entity.AppFile;
import com.boarsoft.boar.entity.FileInfo;
import com.boarsoft.boar.file.action.FileAction;
import com.boarsoft.boar.service.FileService;
import com.boarsoft.common.Util;
import com.boarsoft.common.dao.PagedResult;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/file")
public class ConfigFileAction extends FileAction {
	private static final Logger log = LoggerFactory.getLogger(ConfigFileAction.class);

	@Autowired
	private ConfigFileService configFileSvc;
	@Autowired
	private FileService fileSvc;
	@Autowired
	protected AppBiz appBiz;
	@Autowired
	private ConfigFileService configFileService;
	@Autowired
	private FileVersionAction fileVersionAction;
	@Autowired
	private FileVersionBiz fileVersionBiz;

	@RequestMapping("/list2.do")
	public ReplyInfo<Object> list2(String appId, String appCode, String env, String group) throws IOException {
		if(StringUtil.isNotBlank(appCode)){
			AppInfo appInfo=appBiz.find(appCode);
			if(appInfo==null){
				return new ReplyInfo<>(false,"应用编码["+appCode+"]不存在");
			}
			appId=appInfo.getId();
		}

		PagedResult<AppFile> pr = appFileBiz.list(appId, null, null, 1, 9999);
		List<FileInfo> fLt = new LinkedList<>();
		for (AppFile af : pr.getList()) {
			FileInfo f = af.getFile();
			if("binary".equalsIgnoreCase(f.getEncoding())){
				FileVersion fv = fileVersionBiz.find(f.getId(), env, group);
				f.setContent(fv.getId());
			}else {
				byte[] ba = fileSvc.load(f.getId(), env, group);
				if (ba != null) {
					f.setContent(new String(ba, StandardCharsets.UTF_8));
				}
			}
			fLt.add(f);
		}
		return new ReplyInfo<>(true, new PagedResult<>(fLt.size(), fLt, 1, 9999));
	}

	@RequestMapping("/getByFileName.do")
	public ReplyInfo<Object> getByFileName(String appCode, String fileName, String group, String env) throws IOException {
		AppFile appFile = appFileBiz.getByFileName(appCode, fileName, env);
		if(appFile == null){
			log.error("查询无记录:getByFileName:{}-{}-{}",appCode,fileName,env);
			return new ReplyInfo<Object>(true, null);
		}
		FileInfo f = fileBiz.get(appFile.getFileId());
		byte[] ba = fileSvc.load(f.getId(), env, group);
		if (ba != null && ba.length > 0) {
			f.setContent(new String(ba, "UTF-8"));
		}
		return new ReplyInfo<Object>(true, f);
	}

	@RequestMapping("/getByGroup.do")
	public ReplyInfo<Object> getByGroup(String appCode, String group, String env) throws IOException {
		List<AppFile> appFiles = appFileBiz.getByGroup(appCode, group, env);
		List<FileInfo> fLt = new LinkedList<>();
		for (AppFile af : appFiles) {
			FileInfo f = fileBiz.get(af.getFileId());
			byte[] ba = fileSvc.load(f.getId(), env, group);
			if (ba != null && ba.length > 0) {
				f.setContent(new String(ba, "UTF-8"));
			}
			fLt.add(f);
		}
		return new ReplyInfo<Object>(true, new PagedResult<>(fLt.size(), fLt, 1, 9999));
	}

	@RequestMapping("/sync.do")
	//	@Authorized(code = "config.file.sync")
	public ReplyInfo<Object> sync(String id, String appId, String group) {
		try {
			configFileSvc.sync(id, appId, group);
		} catch (Exception e) {
			log.error("Error on sync config file for app {} group {}", appId, group, e);
			return new ReplyInfo<Object>(e.getMessage());
		}
		return ReplyInfo.SUCCESS;
	}


	@RequestMapping("/load.do")
	//	@Authorized(code = "config.file.load")
	public byte[] load(HttpServletRequest request, String fileId, String env, String group, Integer port, String code) {
		if (Util.strIsNotEmpty(fileId) && Util.strIsNotEmpty(env) && Util.strIsNotEmpty(group)) {
			try {
				return fileSvc.load(fileId, env, group);
			} catch (IOException e) {
				log.error("Error on load config file {} for {}:{}", fileId, env, group);
			}
		}
		if (Util.strIsNotEmpty(code) && port != null) {
			String ip = request.getRemoteAddr();
			try {
				return fileSvc.load(ip, port, code);
			} catch (IOException e) {
				log.error("Error on load config file {} for {}:{}", code, ip, port, e);
			}
		}
		return null;
	}

	/**
	 * 在树上某个应用下增加配置文件需操作两张表 1，向file_info插入配置文件基础数据 2，向app_file插入应用与配置文件的关联关系记录
	 *
	 * @return
	 */
	@JsonIgnoreProperties("apps")
	@RequestMapping("/save.do")
	public ReplyInfo<Object> save(String appId, String appCode, FileConfigInfo a) {
		if (appId == null && appCode != null) {
			AppInfo appInfo=appBiz.find(appCode);
			appId=appInfo.getId();
		}
		if (Util.strIsEmpty(a.getId())) {
			return this.add(appId, a);
		}
		return this.update(appId, a);
	}

	@JsonIgnoreProperties("apps")
	@RequestMapping("/save2.do")
	public ReplyInfo<Object> save2(FileConfigInfo a, MultipartFile file, String appCode,String env,String ver,String group) {
		if(group==null){
			group="default";
		}
		a = (FileConfigInfo) this.save(null,appCode,a).getData();
		FileVersion fv=new FileVersion();
		fv.setFileInfo(a);
		fv.setFileId(a.getId());
		fv.setEnv(env);
		fv.setVer(ver);
		fv.setGroup(group);
		fv = (FileVersion) fileVersionAction.save(fv,file,a.getAppId()).getData();
		fileVersionBiz.active(fv.getId());
		return new ReplyInfo<Object>(true, a);
	}


	@JsonIgnoreProperties("apps")
	@RequestMapping("/add.do")
	//	@Authorized(code = "config.file.add")
	public ReplyInfo<Object> add(String appId, FileConfigInfo a) {
		a.setAppId(appId);
		a.setStatus(FileConfigInfo.STATUS_USED);
		a.setCreateTime(Util.getStdfDateTime());
		a.setLastTime(Util.getStdfDateTime());
		fileBiz.save(appId, a);
		return new ReplyInfo<>(true, a);
	}

	/**
	 * 在树上某个应用下增加配置文件需操作两张表 1，向file_info插入配置文件基础数据 2，向app_file插入应用与配置文件的关联关系记录
	 *
	 * @return
	 */
	@JsonIgnoreProperties("apps")
	@RequestMapping("/update.do")
	//	@Authorized(code = "config.file.update")
	public ReplyInfo<Object> update(String appId, FileConfigInfo o) {
		FileConfigInfo a = (FileConfigInfo) fileBiz.get(o.getId());
		a.setAppId(appId);
		a.setCode(o.getCode());
		a.setName(o.getName());
		a.setType(o.getType());
		a.setDeployPath(o.getDeployPath());
		a.setLastTime(Util.getStdfDateTime());
		a.setMemo(o.getMemo());
		fileBiz.update(appId, a);
		return new ReplyInfo<Object>(true, a);
	}

	@RequestMapping("/clone.do")
	public ReplyInfo<Object> clone(String appId, String fromEnv,String toEnv) {
		//1.调用参数文件服务进行克隆
		configFileService.clone(appId,fromEnv,toEnv);
		return new ReplyInfo<>(true);
	}

	@RequestMapping("/export.do")
	public ResponseEntity<Resource> configExport(String appId, String fromEnv)
			throws FileNotFoundException, MalformedURLException {
		//1.设置导出根目录
		StringBuilder sb=new StringBuilder(BaseConfig.PATH_PRIVATE);
		String exportRoot=sb.append("/").append("configexport")
				.append("/").append(System.currentTimeMillis()).toString();
		String fileName=exportRoot+".zip";
		//2.导出配置文件与表
		configFileService.exportConfig(appId,fromEnv,exportRoot);
		//3.将根目录打成zip包
		ZipUtil.zip(fileName,exportRoot);
		Resource resource =new UrlResource(fileName);
		return ResponseEntity.ok()
				.header("Content-Disposition", "attachment; filename=" + resource.getFilename())
				.body(resource);
	}

	@RequestMapping("/import.do")
	public ReplyInfo<Object> configImport(String zipPath) throws IOException {
		//1.解压zip包
		String importRoot=new StringBuilder(BaseConfig.PATH_PRIVATE)
				.append("/")
				.append("configimport")
				.append("/").toString();
		ZipUtil.unzip(new File(zipPath),importRoot);
		//2.找到配置文件目录，导入配置文件
		configFileService.importConfig(importRoot);
		return new ReplyInfo<>(true);
	}



}